接續昨日的環境,透過 CloudTrail API 紀錄查看是哪時候以及是誰協助關聯 secondary IP 地址給 node 上。以下為部分 AssignPrivateIpAddresses
API 紀錄:
{
"eventVersion": "1.08",
"userIdentity": {
...
...
...
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "AROAYFMQSNSE4F5IBB2AB",
"arn": "arn:aws:iam::111111111111:role/eksctl-ironman-2022-addon-iamserviceaccount-kube-Role1-EMRZZYBVKCRL",
"accountId": "111111111111",
"userName": "eksctl-ironman-2022-addon-iamserviceaccount-kube-Role1-EMRZZYBVKCRL"
},
"webIdFederationData": {
"federatedProvider": "arn:aws:iam::111111111111:oidc-provider/oidc.eks.eu-west-1.amazonaws.com/id/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"attributes": {}
},
"attributes": {
"creationDate": "2022-10-05T13:15:45Z",
"mfaAuthenticated": "false"
}
}
},
"eventTime": "2022-10-05T13:16:06Z",
"eventSource": "ec2.amazonaws.com",
"eventName": "AssignPrivateIpAddresses",
"awsRegion": "eu-west-1",
"sourceIPAddress": "52.210.231.138",
"userAgent": "amazon-vpc-cni-k8s/version/ aws-sdk-go/1.40.6 (go1.16.10; linux; amd64)",
"requestParameters": {
"networkInterfaceId": "eni-0bbea279695112970",
"privateIpAddressesSet": {},
"secondaryPrivateIpAddressCount": 9,
"ipv4Prefixes": {}
},
"responseElements": {
"requestId": "c03ec3be-6a39-4138-9dd9-7d1ed04d7971",
"networkInterfaceId": "eni-0bbea279695112970",
"assignedPrivateIpAddressesSet": {
"assignedPrivateIpAddressSetType": [
{
"privateIpAddress": "192.168.53.76"
},
{
"privateIpAddress": "192.168.41.30"
},
{
"privateIpAddress": "192.168.47.240"
},
{
"privateIpAddress": "192.168.47.144"
},
{
"privateIpAddress": "192.168.61.98"
},
{
"privateIpAddress": "192.168.35.36"
},
{
"privateIpAddress": "192.168.61.68"
},
{
"privateIpAddress": "192.168.51.85"
},
{
"privateIpAddress": "192.168.52.54"
}
]
},
"assignedIpv4PrefixSet": {},
"_return": true
},
...
...
關注到 userAgent 來源為 amazon-vpc-cni-k8s
並關聯了 9 個 private IP 至 eni-0bbea279695112970
也就是 EKS worker node i-03846c730abe852f4
上關聯第二張 Elastic network interfaces(ENI) [1]。
在 VPC 環境中,如果需要建立新的 ENI 資源則需要指定 subnet id,然而 EC2 基於不同的 instance type 也有對應每張 ENI 網卡可以關聯 IP 地址的上限限制。在不同的 EC2 instance type 下,可以關聯 ENI 數量、private IP 地址總數也不進相同。
以 instance type m5.large
為例:最多可以關聯 3 張 ENI,每張 ENI 可最高關聯 10 個 private IP 地址,因此每個 instance type m5.large
EC2 最多可以使用 30 個 private IP。
VPC CNI plugin 中 ipamd
(IP Address Management (IPAM) daemon )元件主要就是負責管理整合一個 IP 地址 warm-pool 並指派 IP 需要使用的 Pod ,倘若若對於 EKS 如何知道使用 VPC CNI plugin 則可以參考 Day5 [2] 說明。
在此討論的是 node 加入 cluster 後 aws-node
Pod 成功執行後的行為。預設額外關聯一張 ENI,並且關聯最多可以關聯的 private IP 地址的上限 [3]。
如同 i-03846c730abe852f4
instance type m5.large
可以觀察到每一張 ENI 都關聯了 10 個 private IP 地址,可藉由 aws ec2 describe-instances
命令查看:
$ aws ec2 describe-instances --instance-ids i-03846c730abe852f4 --query "Reservations[*].Instances[*].NetworkInterfaces[]"
同時,我們也可以觀察到 aws-node
預設設定了環境變數 WARM_ENI_TARGET
為 1。
$ kubectl -n kube-system get ds aws-node -o yaml | grep -A1 "name: WARM"
- name: WARM_ENI_TARGET
value: "1"
- name: WARM_PREFIX_TARGET
value: "1"
WARM_ENI_TARGET
代表 ipamd
保留多少可用的 ENI 數量。以預設設定為例,除了原先 ENI 之外,額外關聯一張 ENI 並關聯相應 private IP 地址以確保未來 Pod IP 地址可以使用。倘若 IP 數量太少(或太多)時,則會呼叫 EC2 API attach(或 detach) ENI 及 private IP。除了上述 WARM_ENI_TARGET
環境變數之外,VPC CNI plugin 提供了兩個 WARM_IP_TARGET
及 MINIMUM_IP_TARGET
環境變數[4] 可以讓使用者調整 Node 上 IP 數量。
WARM_IP_TARGET
:ipamd
保留多少可用的 IP 地址數量。MINIMUM_IP_TARGET
:ipamd
在 node 上指派 IP 地址的總數「下限」。因此我們可以藉由設定 MINIMUM_IP_TARGET
環境變數來調整預設 VPC CNI plugin 以避免 subnet IP 地址耗盡問題。
$ kubectl set env daemonset -n kube-system aws-node MINIMUM_IP_TARGET=5
daemonset.apps/aws-node env updated
設定環境變數會使 aws-node
重啟,待幾分鐘後,再次使用 describe-instances
檢視 IP 地址數量,確認 IP 地址數量僅剩 5 個。
$ $ aws ec2 describe-instances --instance-ids i-03846c730abe852f4 --query Reservations[*].Instances[*].NetworkInterfaces[*].PrivateIpAddresses[*].PrivateIpAddress
[
[
[
[
"192.168.55.245",
"192.168.49.56",
"192.168.41.36",
"192.168.49.142",
"192.168.45.23",
"192.168.62.119"
]
]
]
]
在小型或是 Pod 穩定的 cluster 可以設定 WARM_IP_TARGET
作為保留 Pod IP 地址數量,同時也可以設定 MINIMUM_IP_TARGET
略高於計劃在每個 node 上執行的 pod 的預期數量。
避免將 WARM_IP_TARGET
數值設定太低,這可能會導致呼叫過多次數 EC2 API 導致 API throttling。 對於大型集群,則可以搭配 MINIMUM_IP_TARGET
一起使用以避免 API throttling。
根據 VPC CNI plugin YAML manifest [5],也提供 61678
port metrics 可讓使用者監控當前 node 上的 IP 地址。
...
containers:
- name: aws-node
image: "602401143452.dkr.ecr.us-west-2.amazonaws.com/amazon-k8s-cni:v1.11.4"
ports:
- containerPort: 61678
name: metrics
..
以下為登入其中一台 EKS worker node 進行測試:
[ec2-user@ip-192-168-18-190 ~]$ sudo netstat -ntupl | grep "61678"
tcp6 0 0 :::61678 :::* LISTEN 11283/./aws-k8s-age
[ec2-user@ip-192-168-18-190 ~]$ ps auxf | grep -B2 "11283"
...
...
root 11213 0.0 0.1 712204 9892 ? Sl 15:32 0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 13b9c3b2469aaa79ef46b1f67bc91a8e9ce2e18d0a9330935fc44fb8f9040ec4 -address /run/containerd/containerd.sock
root 11232 0.0 0.0 11556 2604 ? Ss 15:32 0:00 \_ bash /app/entrypoint.sh
root 11283 0.0 0.7 760228 57028 ? Sl 15:32 0:00 \_ ./aws-k8s-agen
[ec2-user@ip-192-168-18-190 ~]$ curl -s localhost:61678/metrics | grep "ip_addresses"
# HELP awscni_assigned_ip_addresses The number of IP addresses assigned to pods
# TYPE awscni_assigned_ip_addresses gauge
awscni_assigned_ip_addresses 2
# HELP awscni_total_ip_addresses The total number of IP addresses
# TYPE awscni_total_ip_addresses gauge
awscni_total_ip_addresses 12
上述輸出為 aws-k8s-agent
process 使用 61678
port,此正是 aws-node
Pod 的 ipamd
,並於 node 上提供 Prometheus [6] 格式指標。
VPC CNI plugin 提供了三個不同 WARM_ENI_TARGET
、WARM_IP_TARGET
及 MINIMUM_IP_TARGET
環境變數讓使用者可以更好的調整 ipamd
調整每個 node 上 warm pool 方式。
倘若需要進行監控每個 node 上 IP 數量最佳化,則可以透過 Prometheus 來收集 61678
port metrics。
WARM_ENI_TARGET
, WARM_IP_TARGET
and MINIMUM_IP_TARGET
- https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/eni-and-ip-target.md